package com.lemons.hackaton.app.data;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.lemons.hackaton.obj.Activity;
import com.lemons.hackaton.obj.Journey;
import com.lemons.hackaton.obj.Person;

public class ReadXML {
	private static String dataFileName = "dataset";

	private static final String CAPACITY = "capacity";
	private static final String MIN_NO_OF_PARTICIPANTS = "minNoOfParticipants";
	private static final String TICKET_PRICE = "ticketPrice";
	private static final String CONTINOUS_OPEN_HOURS = "continuousOpenHours";
	private static final String MAINTAINANCE_HOURS = "maintenanceHours";

	private static final String NAME = "name";
	private static final String BUDGET = "budget";
	private static final String PREFERENCES = "preferences";
	private static final String CONTINUOUSSLEEPTIME = "continuousSleepTime";
	private static final String MAXAWAKETIME = "maxAwakeTime";

	public static Journey readXML(String dataLocation) {
		Journey journey = new Journey();

		List<Activity> activities = new ArrayList<Activity>();
		List<Person> persons = new ArrayList<Person>();
		List<String>personDictionary = new ArrayList<String>();
		try {

			File fXmlFile = new File(dataLocation + "//" + dataFileName + ".xml");
			DocumentBuilderFactory dbFactory = DocumentBuilderFactory
					.newInstance();
			DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
			Document doc = dBuilder.parse(fXmlFile);

			// optional, but recommended
			// read this -
			// http:stackoverflow.com/questions/13786607/normalization-in-dom-parsing-with-java-how-does-it-work
			doc.getDocumentElement().normalize();

			////System.out.println("Root element :"
			//		+ doc.getDocumentElement().getNodeName());

			NodeList nl = doc.getElementsByTagName(doc.getDocumentElement()
					.getNodeName());
			Node n = nl.item(0);
			if (n.getNodeType() == Node.ELEMENT_NODE) {

				Element eElement = (Element) n;

				String duration = (String) eElement.getAttribute("duration");

				if (duration != null) {
					try {
						journey.setDuration(Integer.parseInt(duration));
					} catch (Exception ex) {
						System.out
								.println("Eroare la stabilit durata am pus : 0 ");
						journey.setDuration(0);
					}
				}
			}

			NodeList nlActivities = doc.getElementsByTagName("activities");

			for (int temp = 0; temp < nlActivities.getLength(); temp++) {

				Node nNode = nlActivities.item(temp);

				////System.out.println("\nCurrent Element :" + nNode.getNodeName());

				if (nNode.getNodeType() == Node.ELEMENT_NODE) {

					Element eElement = (Element) nNode;
					NodeList activitiesNL = eElement.getChildNodes();
					for (int i = 0; i < activitiesNL.getLength(); i++) {
						Node nActivity = activitiesNL.item(i);
						if (nActivity.getNodeType() == Node.ELEMENT_NODE) {
//							//System.out.println("nActivity: "
//									+ nActivity.getNodeName());

							Element el = (Element) nActivity;

							String name = el.getNodeName();
//							//System.out.println("name" + name);
							
							String minNoOfParticipants = "";
							String capacity = "";
							String ticketPrice = "";
							String continuousOpenHours = "";
							String maintenanceHours ="";
							try {
								minNoOfParticipants = el.getElementsByTagName(MIN_NO_OF_PARTICIPANTS).item(0).getTextContent();
							} catch (NullPointerException e) {
								minNoOfParticipants = "0";
							}
							
							try {
								capacity = el.getElementsByTagName(CAPACITY).item(0).getTextContent();
								ticketPrice = el.getElementsByTagName(TICKET_PRICE).item(0).getTextContent();
								continuousOpenHours = el.getElementsByTagName(CONTINOUS_OPEN_HOURS).item(0).getTextContent();
								maintenanceHours = el.getElementsByTagName(MAINTAINANCE_HOURS).item(0).getTextContent();
							} catch (NullPointerException e) {
									continue;
							}

							Activity activity = new Activity();

							activity.setName(name);
							try {
								activity.setCapacity(Integer.valueOf(capacity));
							} catch (Exception ex) {
								activity.setCapacity(0);
							}
							try {
								activity.setContinuousOpenHours(Integer
										.valueOf(continuousOpenHours));
							} catch (Exception ex) {
								activity.setContinuousOpenHours(0);
							}
							try {
								activity.setMaintenanceHours(Integer
										.valueOf(maintenanceHours));
							} catch (Exception ex) {
								activity.setMaintenanceHours(0);
							}
							try {
								activity.setMinNoOfParticipants(Integer
										.valueOf(minNoOfParticipants));
							} catch (Exception ex) {
								activity.setMinNoOfParticipants(0);
							}
							try {
								activity.setTicketPrice(Float
										.valueOf(ticketPrice));
							} catch (Exception ex) {
								activity.setTicketPrice(0f);
							}
							activities.add(activity);

						}
					}
				}
			}

			NodeList nlPersons = doc.getElementsByTagName("person");

			for (int temp = 0; temp < nlPersons.getLength(); temp++) {

				Node nNode = nlPersons.item(temp);

//				//System.out.println("PERSONS :" + nNode.getNodeName());

				if (nNode.getNodeType() == Node.ELEMENT_NODE) {

					Element eElement = (Element) nNode;
					String name = "";
					String budget = "";
					String preferences = "";
					
						name = eElement.getElementsByTagName(NAME).item(0).getTextContent();
						System.out.println(" person name: " + name);
						budget = eElement.getElementsByTagName(BUDGET).item(0).getTextContent();
						
						preferences = null;
						NodeList nlPrefs = eElement.getElementsByTagName(PREFERENCES);
						if(nlPrefs!=null&&nlPrefs.getLength()>0){
						  preferences = nlPrefs.item(0).getTextContent();
						} else {
							preferences = null;
						}
					
					
					String continuousSleepTime = "";
					String maxAwakeTime = "";
					
						continuousSleepTime= eElement.getElementsByTagName(CONTINUOUSSLEEPTIME).item(0).getTextContent();
						maxAwakeTime = eElement.getElementsByTagName(MAXAWAKETIME).item(0).getTextContent();
										
					Person pers = new Person();

					pers.setName(name);
					try {
						pers.setBudget(Float.valueOf(budget));
					} catch (Exception ex) {
						pers.setBudget(0f);
					}
					try {
						pers.setContinuousSleepTime(Integer
								.valueOf(continuousSleepTime));
					} catch (Exception ex) {
						pers.setContinuousSleepTime(0);
					}
					try {
						pers.setMaxAwakeTime(Integer.valueOf(maxAwakeTime));
					} catch (Exception ex) {
						pers.setMaxAwakeTime(0);
					}

					if(preferences!=null){
						Set<String> prefs = new HashSet<String>();
						StringTokenizer st2 = new StringTokenizer(preferences, " ");
						 
						while (st2.hasMoreElements()) {
							prefs.add((String)st2.nextElement());
						}
						pers.setPreferences(prefs);
					}
					
					persons.add(pers);
					personDictionary.add(pers.getName());
				}
			}


		} catch (Exception ex) {
			ex.printStackTrace();
		}

		journey.setActivities(activities);
		journey.setPersons(persons);
		Journey.setPersonDictionary(personDictionary);
		Journey.setActivityDictionary(parseXSDSchemaForActivities(dataLocation));
		

//		//System.out.println("JOURNEY AFTER XML \n" + journey);

		return journey;
	}
	
	public static List<String> parseXSDSchemaForActivities(String dataLocation) {
//		boolean valid = validateXMLSchema(dataLocation + "//" + dataFileName + ".xml", dataLocation + "\\journey.xsd");
//		//System.out.println("#########"+valid);
		List<String> activities = new ArrayList<String>();
		try {

			// read the xsd file from the location
			File file = new File(dataLocation + "\\journey.xsd");

			// parse the document
			DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory
					.newInstance();
			DocumentBuilder docBuilder;
			docBuilder = docBuilderFactory.newDocumentBuilder();
			Document doc = docBuilder.parse(file);
			NodeList list = doc.getElementsByTagName("xsd:element");
            
			List<String> refs = new ArrayList<String>();

			for (int i = 0; i < list.getLength(); i++) {
				Element first = (Element) list.item(i);
				if (first.hasAttributes()) {
					String nm = first.getAttribute("name");
					if("activities".equalsIgnoreCase(first.getAttribute("name"))){
						NodeList nl1 = first.getChildNodes();

						for(int j=0;j<nl1.getLength();j++){
							Node n1 = nl1.item(j);
							
							if(n1.getNodeType() == Node.ELEMENT_NODE) {
								//System.out.println("#####n1 : "+ n1.getNodeName());
								NodeList nl2 = n1.getChildNodes();

								for(int k=0;k<nl2.getLength();k++){
									Node n2 = nl2.item(k);
									
									if(n2.getNodeType() == Node.ELEMENT_NODE) {
										//System.out.println("#####n2: "+ n2.getNodeName());

										NodeList nl3 = n2.getChildNodes();

										for(int l=0;l<nl3.getLength();l++){
											Node n3 = nl3.item(l);
											
											if(n3.getNodeType() == Node.ELEMENT_NODE) {
												//System.out.println("#####n3: "+ n3.getNodeName());
												Element el = (Element)n3;
												String ref = el.getAttribute("ref");
												//System.out.println("#####n3.ref: " + ref);
												if(ref!=null&&ref.length()>0){
													refs.add(ref);
											    }
												String aName = el.getAttribute("name");
												//System.out.println("#####n3.name: " + aName);
												if(aName!=null&&aName.length()>0){
													activities.add(aName);
												}
												//System.out.println("#####n3.type: " + el.getAttribute("type"));
											}
										}

									}
								}
							}
						}
					}
				}
			}
		
			//System.out.println(">>>>refs : "+refs);
			NodeList nl = doc.getElementsByTagName("xsd:element");
			for(int i=0;i<nl.getLength();i++){
				Node node = nl.item(i);
				if(node.getNodeType() == Node.ELEMENT_NODE){
					Element el = (Element)node;
					for(int j=0;j<refs.size();j++){
						String ref = refs.get(j);
						if(ref.equalsIgnoreCase(el.getAttribute("type"))){
							String name = el.getAttribute("name");
							activities.add(name);
						}
					}
				}
			}
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException ed) {
			ed.printStackTrace();
		}
		
		
		//System.out.println(">>>>activities : "+activities);
		
		return activities;
	}
	
	
	
    public static boolean validateXMLSchema(String xsdPath, String xmlPath){
        
        try {
            SchemaFactory factory =
                    SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
            Schema schema = factory.newSchema(new File(xsdPath));
            Validator validator = schema.newValidator();
            validator.validate(new StreamSource(new File(xmlPath)));
        } catch (IOException e) {
            //System.out.println("Exception: "+e.getMessage());
            return false;
        } catch ( SAXException e){
        	//System.out.println("Exception: "+e.getMessage());
        }
        return true;
    }		

}
